<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>贪吃蛇游戏</title>
<style>
body {
  width: 200px;
  margin: auto;
}
#c {
  border: 2px solid #d3d3d3;
  margin-top: 10px;
}
</style>
</head>
<body>
  <canvas id="c" width="200" height="200"></canvas>
  <p>用ASDW键控制</p>
</body>
</html>
<script>
//(function () {

  var canvas  = document.getElementById('c');
  var context = canvas.getContext('2d');
  var width = 20;
  var height = 20;

  // 不同方向前进时对坐标的计算
  var KEYCODE = {LEFT: 97, DOWN: 115, RIGHT: 100, UP: 119};
  var DIRECT = {};
  DIRECT[KEYCODE.LEFT] = {x: -1, y: 0};
  DIRECT[KEYCODE.RIGHT] = {x: 1, y: 0};
  DIRECT[KEYCODE.UP] = {x: 0, y: -1};
  DIRECT[KEYCODE.DOWN] = {x: 0, y: 1};

  // 当前身体位置
  var pointBody = [{
    x: parseInt(width / 2, 10),
    y: parseInt(height / 2, 10),
    d: KEYCODE.UP
  }];
  // 当前食物的位置
  var pointFood = randomPoint();

  // 按键处理
  window.addEventListener('keypress', function (e) {
    if (DIRECT[e.keyCode]) pointBody[0].d = e.keyCode;
  });

  // 画点
  var pointWidth = canvas.width / width;
  var pointHeight = canvas.height / height;
  function drawPoint (p, a, b, color) {
    context.fillStyle = color || '#aaa';
    context.strokeStyle = '#fff';
    context.strokeRect(p.x * pointWidth, p.y * pointHeight, pointWidth, pointHeight);
    context.fillRect(p.x * pointWidth, p.y * pointHeight, pointWidth, pointHeight);
  }

  // 随机生成一个点
  function randomPoint () {
    var p = {x: parseInt(Math.random() * width, 10), y: parseInt(Math.random() * height, 10)};
    return pointBody.some(function (p2) { return p.x === p2.x && p.y === p2.y; }) ? randomPoint() : p;
  }

  // 游戏结束
  function gameOver () {
    clearInterval(tidLoop);
    context.fillStyle = '#f00';
    context.font = 'bold 24px 宋体';
    context.fillText('游戏结束', (canvas.width - 24 * 4) / 2, (canvas.height - 24) / 2);
  }

  // 计算下一点的位置
  function computeNextPoint (p) {
    var d = DIRECT[p.d];
    return {x: p.x + d.x, y: p.y + d.y, d: p.d};
  }

  // 游戏时钟
  var tidLoop = setInterval(function gameLoop () {
    // 检查是否撞墙或者撞到自己
    var headPoint = computeNextPoint(pointBody[0]);
    if (!(headPoint.x >= 0 && headPoint.x < width && headPoint.y >= 0 && headPoint.y < height)) return gameOver();
    for (var i = 0; i < pointBody.length; i++) {
      if (headPoint.x === pointBody[i].x && headPoint.y === pointBody[i].y) return gameOver();
    }

    // 检查是否吃到了食物，则只移动头一个点即可，需要重新生成一个点，否则需要去掉最后一个点
    pointBody.unshift(headPoint);
    if (pointFood.x === headPoint.x && pointFood.y === headPoint.y) {
      pointFood = randomPoint();
    } else {
      pointBody.pop();
    }

    // 绘制画面
    context.fillStyle = '#f1fedd';
    context.fillRect(0, 0, canvas.width, canvas.height);
    drawPoint(pointFood, 0, 0, '#e96900');
    drawPoint(pointBody[0], 0, 0, '#2d64b3');
    pointBody.slice(1).forEach(drawPoint);
  }, 200);

//})();
</script>